package loaders;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;

import mesh.Mesh;

import org.lwjgl.BufferUtils;

import utils.ResourceRetriever;

public class OBJLoader
{
	//Vertex data
	private static final String VERTICES = "v";
	private static final String UV = "vt";
	private static final String NORMAL = "vn";
	private static final String SPACE_VERTICES = "vp";
	private static final String NON_RATIONAL_SURFACE_TYPE= "cstype";
	private static final String DEGREE = "deg";
	private static final String BASIS_MATRIX = "bmat";
	private static final String STEP_SIZE = "step";
	
	//Elements
	private static final String POINT = "p";
	private static final String LINE = "l";
	private static final String FACE = "f";
	private static final String CURVE = "curv";
	private static final String CURVE_2D = "curv2";
	private static final String SURFACE = "surf";
	
	//Free-form curve / surface body statments
	private static final String PARAMETER_VALUES = "parm";
	private static final String OUTER_TRIMMING_GROUP = "trim";
	private static final String INNER_TRIMMING_GROUP = "hole";
	private static final String SPECIAL_CURVE = "scurv";
	private static final String SPECIAL_POINT = "sp";
	private static final String END_STATMENT = "end";
	
	//Connectivity between free-form surfaces
	private static final String CONNECT = "con";
	
	//Grouping
	private static final String GROUP_NAME = "g";
	private static final String SMOOTHING_GROUP = "s";
	private static final String MERGING_GROUP = "mg";
	private static final String OBJECT_NAME = "o";
	
	//Display rendering attributes
	private static final String BEVEL_INTERPOLATION = "bevel";
	private static final String COLOR_INTERPOLATION = "c_interp";
	private static final String DISSOLVE_INTERPOLATION = "d_interp";
	private static final String LOD = "lod";
	private static final String MATERIAL_NAME = "usemtl";
	private static final String MATERIAL_LIBRARY = "mtllib";
	private static final String SHADOW_CASTING = "shadow_obj";
	private static final String RAY_TRACING = "trace_obj";
	private static final String CURVE_APPROXIMATION_TECH = "ctech";
	private static final String SURFACE_APPROXIMATION_TECH = "stech";
	
	
	
	
	private StringBuilder contents;
	
	private float[] vertices;
	private ArrayList<Float> vertsList;
	
	private ArrayList<Float> uvIndexes;
	private float[] uvs;
	private ArrayList<float[]> uvList;
	
	private float[] normals;
	private ArrayList<Float> normalsList;
	
	private int[] faces;
	private ArrayList<Integer> facesList;
	
	private int[] inds;
	
//	private Context context;
	
	public OBJLoader()
	{
	}
	
	public void loadFile( String path )
	{
		BufferedReader bufferedReader = null;
		
		try
		{
			bufferedReader = new BufferedReader(new InputStreamReader(ResourceRetriever.getResourceAsStream(path)));
		} catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		
		String line;
		contents = new StringBuilder();
		
		vertsList = new ArrayList<Float>();
		facesList = new ArrayList<Integer>();
		normalsList = new ArrayList<Float>();
		uvIndexes = new ArrayList<Float>();
		uvList = new ArrayList<float[]>();
		
		try
		{
			while( (line = bufferedReader.readLine()) != null )
			{				
				getData( line );
			}
			
		}
		catch( IOException e )
		{
			System.out.println(" shit");
		}
		
		setData();
	}
	
	private void getData( String l )
	{
		String[] dataArray = l.split(" ");
		String type = dataArray[0];
		
		if( type.equals( VERTICES ) )addVertices(dataArray);
		else if( type.equals( UV ) ) addUV(dataArray);
		else if( type.equals( NORMAL ) ) addNormal(dataArray);
		else if( type.equals(FACE) ) addFaces(dataArray);
	}

	private void setData()
	{
		//vertices
		vertices = new float[ vertsList.size() ];
		for( int i = 0; i < vertsList.size(); i++ )
			vertices[i] = vertsList.get( i );
		
		//uvs
		uvs = new float[ uvIndexes.size() ];
		for( int i = 0; i < uvIndexes.size(); i++ )
			uvs[i] = uvIndexes.get( i );
		//normals
		normals = new float[ normalsList.size() ];
		for( int i = 0; i < normalsList.size(); i++ )
			normals[i] = normalsList.get( i );
		
		//faces
		faces = new int[ facesList.size() ];
		for( int i = 0; i < facesList.size(); i++ )
		{
			faces[i] = facesList.get( i );
		}
		
	}
	
	private void addVertices( String[] data )
	{
		vertsList.add( Float.valueOf(data[1].trim()).floatValue() );
		vertsList.add( Float.valueOf(data[2].trim()).floatValue() );
		vertsList.add( Float.valueOf(data[3].trim()).floatValue() );
	}
	
	private void addUV( String[] data )
	{
		float[] UVS = new float[2];
		UVS[0] = Double.valueOf(data[1].trim()).floatValue();
		UVS[1] = Double.valueOf(data[2].trim()).floatValue();
		
		uvList.add(UVS);
	}
	
	private void addNormal( String[] data )
	{
		normalsList.add( Float.valueOf(data[1].trim()).floatValue() );
		normalsList.add( Float.valueOf(data[2].trim()).floatValue() );
		normalsList.add( Float.valueOf(data[3].trim()).floatValue() );
	}
	
	private void addFaces( String[] data )
	{
		facesList.add( Integer.valueOf(data[1].split("/")[0]) - 1 );
		facesList.add( Integer.valueOf(data[2].split("/")[0]) - 1 );
		facesList.add( Integer.valueOf(data[3].split("/")[0]) - 1 );
	}
	
	public String data()
	{
		return contents.toString();
	}
	
	public Mesh getMesh()
	{
		Mesh m = new Mesh();
//		m.setData(vertices, faces);
		
		return m;
	}
	
	public float[] getVertices()
	{
		return vertices;
	}
	
	public int[] getFaces()
	{
		return faces;
	}
	
	public float[] getUVS()
	{
		return uvs;
	}
	
	public float[] getNormals()
	{
		return normals;
	}
	
	public FloatBuffer getVertexBuffer()
	{
		FloatBuffer vb = BufferUtils.createFloatBuffer(vertsList.size());
		
		for( int i = 0; i < vertsList.size(); i++ )
		{
			vb.put(vertsList.get(i));
		}
		
		return vb;
	}
	
	public IntBuffer getIndexBuffer()
	{
		IntBuffer ib = BufferUtils.createIntBuffer(facesList.size());
		
		for( int i = 0; i < facesList.size(); i++ )
			ib.put(facesList.get(i));
		return ib;
	}
	
	public FloatBuffer getUVSBuffer()
	{
		FloatBuffer ub = BufferUtils.createFloatBuffer(uvs.length * 2);
		
		for( int i = 0; i < uvs.length; i++ )
			ub.put(uvs[i]);
		
		return ub;
	}
}
